import rclpy
from rclpy.node import Node
import selectors
import socket
import types
 
 
class MockServer(Node):
    def __init__(self):
        self._sel = selectors.DefaultSelector()  # 默认的选择器类，使用当前平台上可用的最高效实现，大多数用户的默认选择
        self._bufsize = 1024
 
    def start(self):
        self.register()
        self.listen()
 
    def register(self):
        # 创建套接字 AF_INET = 面向网络， AF_UNIX = 面向文件， SOCKET_STREAM = TCP， SOCK_DGRAM = UDP
        conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # SO_REUSEADDR: 一个端口释放后会等待两分钟之后才能再被使用，加该选项后是让端口释放后立即就可以被再次使用，可以规避TIME_WAIT状态
        conn.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        conn.bind(('', 9760))
        conn.listen()
        # 非阻塞模式，遇到问题会跑出异常。在阻塞模式下，遇到问题并不会阻止操作
        conn.setblocking(False)
        # 注册事件
        self._sel.register(conn, selectors.EVENT_READ, data=None)
 
    def listen(self):
        while True:
            events = self._sel.select(timeout=None)
            for key, mask in events:
                if key.data is None:
                    self.accept(key.fileobj)
                else:
                    self.process(key, mask)
 
    def accept(self, sock):
        print('do accept')
        conn, addr = sock.accept()
        conn.setblocking(False)
        data = types.SimpleNamespace(addr=addr, buffer=b'')
        events = selectors.EVENT_READ
        self._sel.register(conn, events, data=data)
        dataStr = 'ok'
        conn.send(dataStr.encode() );
 
    def process(self, key, mask):
        okStr = 'ok'
        print('do process')
        sock = key.fileobj
        data = key.data
        if mask & selectors.EVENT_READ:
            try:
                bytesbuffer = sock.recv(self._bufsize)
                if bytesbuffer:
                    buffer = bytesbuffer.decode()
                    print('addr:' + str(data.addr) + ', len:' + str(len(buffer)) + ', buffer:' + buffer)
                    socket.sendall(okStr.encode() )
                    #sock.setsockopt(socket.SOL_TCP, socket.TCP_QUICKACK, 0)
                else:
                    print('not data '  )
                    #self._sel.unregister(sock)
                    #sock.close()
            except ConnectionResetError as e:
                print('closing connection to' + str(data.addr))
                self._sel.unregister(sock)
                sock.close()
def main(args=None):
    rclpy.init(args=args)
    server = MockServer()
    server.start()
    rclpy.spin(server)

    server.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()
